﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Json;
using UtilZ.Dotnet.Ex.ValueDescription;
using UtilZ.Dotnet.Ex.ZLog;

namespace UtilZ.Dotnet.Ex.ParaManagement
{
    /// <summary>
    /// 参数管理器
    /// </summary>
    public class ParaManager
    {
        /// <summary>
        /// 获取一个用于同步访问当前对象的锁
        /// </summary>
        public readonly object SyncRoot = new object();

        /// <summary>
        /// 参数字典集合[key;参数名;value:参数值]
        /// </summary>
        private readonly ConcurrentDictionary<string, object> _dic = new ConcurrentDictionary<string, object>();

        /// <summary>
        /// 临时参数字典
        /// </summary>
        private readonly ConcurrentDictionary<string, object> _tempDic = new ConcurrentDictionary<string, object>();


        private ParaStoreType _storeType = ParaStoreType.Forever;
        /// <summary>
        /// 参数存储类型
        /// </summary>
        public ParaStoreType StoreType
        {
            get { return this._storeType; }
            set
            {
                if (this._storeType == value)
                {
                    return;
                }

                this._storeType = value;
                if (this._storeType == ParaStoreType.Forever)
                {
                    this.PersistentToForever();
                }
            }
        }



        private bool _paraChanged = false;
        /// <summary>
        /// 参数改变通知事件
        /// </summary>
        private event EventHandler<ParaChangeArgs> _onParaChanged = null;
        /// <summary>
        /// 参数改变通知事件
        /// </summary>
        public event EventHandler<ParaChangeArgs> OnParaChanged
        {
            add
            {
                _onParaChanged += value;
            }
            remove
            {
                _onParaChanged -= value;
            }
        }

        /// <summary>
        /// 参数变更后,是否需要输出通知[true:需要输出通知;false:不需要输出通知]
        /// </summary>
        /// <returns>true:需要输出通知;false:不需要输出通知</returns>
        protected bool HasParaChangedNotify()
        {
            return this._onParaChanged != null;
        }

        /// <summary>
        /// 触发参数改变通知事件
        /// </summary>
        /// <param name="args">事件参数</param>
        protected void OnRaiseParaChanged(ParaChangeArgs args)
        {
            var handler = this._onParaChanged;
            if (handler == null)
            {
                this._paraChanged = false;
                return;
            }

            if (this._enableParaChanged)
            {
                this._paraChanged = false;
                handler.Invoke(this, args);
            }
            else
            {
                this._paraChanged = true;
            }
        }


        private bool _enableParaChanged = true;
        /// <summary>
        /// 是否启用参数改变通知[true:启用(参数变化触发参数改变通知事件);false:禁用,参数改变后不触发参数改变通知事件]
        /// </summary>
        public bool EnableParaChanged
        {
            get { return this._enableParaChanged; }
            set
            {
                this._enableParaChanged = value;
                if (value && this._paraChanged)
                {
                    this.OnRaiseParaChanged(null);
                }
            }
        }


        /// <summary>
        /// 获取正式参数个数
        /// </summary>
        public int Count
        {
            get
            {
                return this._dic.Count;
            }
        }

        /// <summary>
        /// 参数不存在解决事件
        /// </summary>
        private event EventHandler<ParaResolveEventArgs> _resolving;
        /// <summary>
        /// 参数不存在解决事件
        /// </summary>
        public event EventHandler<ParaResolveEventArgs> Resolving
        {
            add
            {
                this._resolving += value;
            }
            remove
            {
                this._resolving -= value;
            }
        }

        private IParaConverter _converter = null;
        /// <summary>
        /// 获取或设置参数转换器
        /// </summary>
        public IParaConverter Converter
        {
            get { return this._converter; }
            set { this._converter = value; }
        }


        /// <summary>
        /// 当前对象标记数据
        /// </summary>
        public object Tag { get; set; } = null;





        private readonly string _filePath = null;
        private readonly string _name = null;
        /// <summary>
        /// 设备名称
        /// </summary>
        public string Name
        {
            get { return this._name; }
        }





        /// <summary>
        /// 构造函数-参数无需保存到文件
        /// </summary>
        /// <param name="name">参数管理器名称</param>
        public ParaManager(string name = null)
             : base()
        {
            this._name = name;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="filePath">参数文件存放路径</param>
        /// <param name="name">参数管理器名称</param>
        public ParaManager(string filePath, string name)
            : base()
        {
            this._name = name;
            this._filePath = filePath;

            try
            {
                this.Load(filePath);
            }
            catch (Exception ex)
            {
                string fileNameNoExtension = Path.GetFileNameWithoutExtension(filePath);
                string dir = Path.GetDirectoryName(filePath);
                string newFilePath = Path.Combine(dir, $"{fileNameNoExtension}_{DateTime.Now.ToString("yyyy-MM-dd_HH_mm_ss")}{Path.GetExtension(filePath)}");
                ZLoger.Warn(ex, $"因为某些意外因素导致存放设备\"{name}\"参数的xml格式异常，重命名文件\"{filePath}\"为\"{newFilePath}\"");
                try
                {
                    File.Move(filePath, newFilePath);
                }
                catch (Exception exi)
                {
                    ZLoger.Error(exi, $"因为某些意外因素导致存放设备\"{name}\"参数的xml格式异常，重命名文件\"{filePath}\"为\"{newFilePath}\"失败.");
                }
            }
        }


        #region 从文件中读取参数和将参数写到文件中

        //参数xml中元素名定义
        private const string _ELE_ROOT = "root";
        private const string _ELE_PARA = "Para";
        private const string _ELE_PARA_NAME = "Name";
        private const string _ELE_PARA_TYPE = "Type";
        private const string _ELE_PARA_VALUE = "Value";
        private const string _CUSTOMER = "Cus";

        /// <summary>
        /// 从本地文件中加载参数到当前参数管理器中
        /// </summary>
        /// <param name="filePath">本地参数文件路径</param>
        /// <exception cref="ArgumentNullException"></exception>
        public void Load(string filePath)
        {
            if (string.IsNullOrEmpty(filePath))
            {
                throw new ArgumentNullException(nameof(filePath));
            }

            if (!File.Exists(filePath))
            {
                ZLoger.Info($"参数文件\"{filePath}\"不存在,不加载本地参数...");
                return;
            }

            lock (this.SyncRoot)
            {
                XDocument xdoc = XDocument.Load(filePath);
                var paraEles = xdoc.Root.Elements(_ELE_PARA);
                Type valueType;
                string paraName;
                object value, oldValue;
                XAttribute attri;

                bool hasParaChangedNotify = this.HasParaChangedNotify();
                List<ParaChangeItem> addParas = null, upgradeParas = null;

                foreach (var paraEle in paraEles)
                {
                    paraName = XmlEx.GetXElementAttributeValue(paraEle, _ELE_PARA_NAME);

                    //写入自定义标记
                    if (paraEle.Attribute(_CUSTOMER) != null)
                    {
                        //自定义
                        if (this._converter == null)
                        {
                            ZLoger.Warn($"文件\"{filePath}\"工作参数:\"{paraName}\"值对应在数据为自定义读写,但未指定读取器,读取失败,忽略该参数");
                            continue;
                        }
                        else
                        {
                            if (!this._converter.TryReadFrom(paraEle, paraName, out value))
                            {
                                ZLoger.Warn($"文件\"{filePath}\"工作参数:\"{paraName}\"值对应在数据为自定义读写,但读取失败,忽略该参数");
                                continue;
                            }
                        }
                    }
                    else
                    {
                        valueType = Type.GetType(XmlEx.GetXElementAttributeValue(paraEle, _ELE_PARA_TYPE));
                        if (valueType == null)
                        {
                            ZLoger.Warn($"文件\"{filePath}\"工作参数:\"{paraName}\"值对应在数据类型失败,忽略该参数");
                            continue;
                        }

                        attri = paraEle.Attribute(_ELE_PARA_VALUE);
                        if (attri == null)
                        {
                            //参数特性不存在,则该参数值为CDATA
                            value = JsonSerializer.DeserializeObject(paraEle.Value, valueType);
                        }
                        else
                        {
                            if (valueType == TypeEx.StringType)
                            {
                                value = attri.Value;//字符串类型不转换
                            }
                            else
                            {
                                //基础类型
                                try
                                {
                                    value = ConvertEx.ConvertTo(valueType, attri.Value);
                                }
                                catch (Exception exi)
                                {
                                    ZLoger.Warn(exi, $"文件\"{filePath}\"工作参数:\"{paraName}\"字符串值\"{attri.Value}\"转换为类型\"{valueType.AssemblyQualifiedName}\"失败,忽略该参数");
                                    continue;//转换异常,则忽略该参数
                                }
                            }
                        }
                    }

                    if (this._dic.TryGetValue(paraName, out oldValue))
                    {
                        if (object.ReferenceEquals(value, oldValue) || ObjectEx.EqualsEx(value, oldValue))
                        {
                            continue;
                        }
                        else
                        {
                            if (hasParaChangedNotify)
                            {
                                if (upgradeParas == null)
                                {
                                    upgradeParas = new List<ParaChangeItem>();
                                }
                                upgradeParas.Add(new ParaChangeItem(paraName, value, oldValue));
                            }
                        }
                    }
                    else
                    {
                        if (hasParaChangedNotify)
                        {
                            if (addParas == null)
                            {
                                addParas = new List<ParaChangeItem>();
                            }
                            addParas.Add(new ParaChangeItem(paraName, value));
                        }
                    }

                    this._dic[paraName] = value;
                }

                if (hasParaChangedNotify)
                {
                    this.OnRaiseParaChanged(new ParaChangeArgs(addParas, null, upgradeParas));
                }
            }
        }

        /// <summary>
        /// 保存参数到本地文件中
        /// </summary>
        /// <param name="ignoreParaNames">忽略的参数名集合,为null或集合项为空，则不忽略</param>
        public void Save(IEnumerable<string> ignoreParaNames = null)
        {
            if (string.IsNullOrWhiteSpace(this._filePath))
            {
                throw new InvalidOperationException("构造函数未传入路径,保存时需要指定文件路径.");
            }

            this.Save(this._filePath, ignoreParaNames);
        }

        /// <summary>
        /// 保存参数到本地文件中
        /// </summary>
        /// <param name="filePath">本地参数文件路径</param>
        /// <param name="ignoreParaNames">忽略的参数名集合,为null或集合项为空，则不忽略</param>
        public void Save(string filePath, IEnumerable<string> ignoreParaNames = null)
        {
            if (string.IsNullOrEmpty(filePath))
            {
                throw new ArgumentNullException(nameof(filePath));
            }

            lock (this.SyncRoot)
            {
                var xdoc = new XDocument();
                var rootEle = new XElement(_ELE_ROOT);
                xdoc.Add(rootEle);

                XElement paraItemEle;
                Type type;

                foreach (var kv in this._dic)
                {
                    if (kv.Value == null || ignoreParaNames != null && ignoreParaNames.Contains(kv.Key))
                    {
                        //忽略该参数项
                        continue;
                    }

                    paraItemEle = new XElement(_ELE_PARA);
                    paraItemEle.Add(new XAttribute(_ELE_PARA_NAME, kv.Key));

                    type = kv.Value.GetType();
                    paraItemEle.Add(new XAttribute(_ELE_PARA_TYPE, type.AssemblyQualifiedName));

                    if (this._converter != null && this._converter.TryWriteTo(paraItemEle, kv.Key, kv.Value))
                    {
                        //写入自定义标记
                        paraItemEle.Add(new XAttribute(_CUSTOMER, "flag"));
                    }
                    else
                    {
                        if (type == TypeEx.StringType)
                        {
                            //字符串类型
                            paraItemEle.Add(new XAttribute(_ELE_PARA_VALUE, (string)kv.Value));
                        }
                        else if (type.IsValueType)
                        {
                            //基础类型
                            paraItemEle.Add(new XAttribute(_ELE_PARA_VALUE, kv.Value.ToString()));
                        }
                        else
                        {
                            //非string的引用类型序列化到CData中
                            paraItemEle.Add(new XCData(JsonSerializer.SerializeObject(kv.Value)));
                        }
                    }

                    rootEle.Add(paraItemEle);
                }

                DirectoryInfoEx.CheckFilePathDirectory(filePath);
                xdoc.Save(filePath);
            }
        }

        #endregion



        #region 设置参数

        /// <summary>
        /// 将临时存储的参数持久化
        /// </summary>
        private void PersistentToForever()
        {
            if (this._tempDic.Count == 0)
            {
                return;
            }

            bool hasParaChangedNotify = this.HasParaChangedNotify();
            List<ParaChangeItem> addParaNames = null, upgradeParaNames = null;
            object oldValue;

            foreach (var kv in this._tempDic)
            {
                if (this._dic.TryGetValue(kv.Key, out oldValue))
                {
                    if (object.ReferenceEquals(oldValue, kv.Value) || ObjectEx.EqualsEx(oldValue, kv.Value))
                    {
                        continue;
                    }
                    else
                    {
                        this._dic[kv.Key] = kv.Value;

                        if (hasParaChangedNotify)
                        {
                            if (upgradeParaNames == null)
                            {
                                upgradeParaNames = new List<ParaChangeItem>();
                            }
                            upgradeParaNames.Add(new ParaChangeItem(kv.Key, kv.Value, oldValue));
                        }
                    }
                }
                else
                {
                    this._dic[kv.Key] = kv.Value;

                    if (hasParaChangedNotify)
                    {
                        if (addParaNames == null)
                        {
                            addParaNames = new List<ParaChangeItem>();
                        }
                        addParaNames.Add(new ParaChangeItem(kv.Key, kv.Value));
                    }
                }
            }
            this._tempDic.Clear();

            if (hasParaChangedNotify &&
                (addParaNames != null || upgradeParaNames != null))
            {
                this.OnRaiseParaChanged(new ParaChangeArgs(addParaNames, null, upgradeParaNames));
            }
        }

        /// <summary>
        /// 设置指定参数名对应的参数值
        /// </summary>
        /// <param name="paraName">参数名</param>
        /// <param name="value">参数值</param>
        /// <exception cref="ArgumentNullException">参数名为null将抛出异常</exception>
        public void Set(string paraName, object value)
        {
            if (string.IsNullOrEmpty(paraName))
            {
                throw new ArgumentNullException(nameof(paraName), "参数名不能为null或空或全空格");
            }

            if (this._storeType == ParaStoreType.Temp)
            {
                this._tempDic[paraName] = value;
            }
            else
            {
                bool hasParaChangedNotify = this.HasParaChangedNotify();
                List<ParaChangeItem> addParas = null, upgradeParas = null;

                this._dic.AddOrUpdate(paraName, value, (key, oldValue) =>
                {
                    if (object.ReferenceEquals(oldValue, value) || ObjectEx.EqualsEx(oldValue, value))
                    {
                        hasParaChangedNotify = false;
                        return oldValue;
                    }
                    else
                    {
                        if (hasParaChangedNotify)
                        {
                            upgradeParas = new List<ParaChangeItem>() { new ParaChangeItem(paraName, value, oldValue) };
                        }

                        return value;
                    }
                });

                if (hasParaChangedNotify)
                {
                    if (upgradeParas == null)
                    {
                        addParas = new List<ParaChangeItem>() { new ParaChangeItem(paraName, value) };
                    }

                    this.OnRaiseParaChanged(new ParaChangeArgs(addParas, null, upgradeParas));
                }
            }
        }

        /// <summary>
        /// 添加或更新指定参数名参数值[添加成功或更新成功返回true,无更新返回false]
        /// </summary>
        /// <param name="paraName">参数名</param>
        /// <param name="value">参数值</param>
        /// <exception cref="ArgumentNullException">参数名为null将抛出异常</exception>
        /// <returns>添加成功或更新成功返回true,无更新返回false</returns>
        public bool AddOrUpdate(string paraName, object value)
        {
            if (string.IsNullOrEmpty(paraName))
            {
                throw new ArgumentNullException(nameof(paraName), "参数名不能为null或空或全空格");
            }

            bool result = false;
            if (this._storeType == ParaStoreType.Temp)
            {
                this._tempDic.AddOrUpdate(paraName, value, (key, oldValue) =>
                {
                    if (object.ReferenceEquals(oldValue, value) || ObjectEx.EqualsEx(oldValue, value))
                    {
                        result = false;
                        return oldValue;
                    }
                    else
                    {
                        result = true;
                        return value;
                    }
                });
            }
            else
            {
                bool hasParaChangedNotify = this.HasParaChangedNotify();
                List<ParaChangeItem> addParas = null, upgradeParas = null;

                this._dic.AddOrUpdate(paraName, value, (key, oldValue) =>
                {
                    if (object.ReferenceEquals(oldValue, value) || ObjectEx.EqualsEx(oldValue, value))
                    {
                        hasParaChangedNotify = false;
                        result = false;
                        return oldValue;
                    }
                    else
                    {
                        result = true;
                        if (hasParaChangedNotify)
                        {
                            upgradeParas = new List<ParaChangeItem>() { new ParaChangeItem(paraName, value, oldValue) };
                        }

                        return value;
                    }
                });

                if (hasParaChangedNotify)
                {
                    if (upgradeParas == null)
                    {
                        addParas = new List<ParaChangeItem>() { new ParaChangeItem(paraName, value) };
                    }

                    this.OnRaiseParaChanged(new ParaChangeArgs(addParas, null, upgradeParas));
                }
            }

            return result;
        }

        /// <summary>
        /// 移除参数
        /// </summary>
        /// <param name="paraName">参数名</param>
        public void Remove(string paraName)
        {
            if (string.IsNullOrEmpty(paraName))
            {
                throw new ArgumentNullException(nameof(paraName), "参数名不能为null或空或全空格");
            }

            object value;
            this._tempDic.TryRemove(paraName, out value);
            if (this._dic.TryRemove(paraName, out value))
            {
                if (this.HasParaChangedNotify())
                {
                    this.OnRaiseParaChanged(new ParaChangeArgs(null, new List<ParaChangeItem>() { new ParaChangeItem(paraName, value) }, null));
                }
            }
        }

        /// <summary>
        /// 移除参数
        /// </summary>
        /// <param name="paraNames">参数名集合</param>
        public void Remove(IEnumerable<string> paraNames)
        {
            if (paraNames == null || paraNames.Count() == 0)
            {
                return;
            }

            object value;
            bool hasParaChangedNotify = this.HasParaChangedNotify();
            List<ParaChangeItem> removeParas = null;

            foreach (var paraName in paraNames)
            {
                if (string.IsNullOrEmpty(paraName))
                {
                    throw new ArgumentNullException(nameof(paraNames), $"参数名不能为null或空或全空格.参数\"{nameof(paraNames)}\"集合中有无效参数名项");
                }

                this._tempDic.TryRemove(paraName, out value);
                if (this._dic.TryRemove(paraName, out value))
                {
                    if (hasParaChangedNotify)
                    {
                        if (removeParas == null)
                        {
                            removeParas = new List<ParaChangeItem>();
                        }
                        removeParas.Add(new ParaChangeItem(paraName, value));
                    }
                }
            }

            if (hasParaChangedNotify && removeParas != null)
            {
                this.OnRaiseParaChanged(new ParaChangeArgs(null, removeParas, null));
            }
        }

        /// <summary>
        /// 清空参数
        /// </summary>
        public void Clear()
        {
            this._tempDic.Clear();

            if (this._dic.Count > 0)
            {
                if (this.HasParaChangedNotify())
                {
                    var removeParas = this._dic.Select(kv => { return new ParaChangeItem(kv.Key, kv.Value); }).ToList();
                    this._dic.Clear();
                    this.OnRaiseParaChanged(new ParaChangeArgs(null, removeParas, null));
                }
                else
                {
                    this._dic.Clear();
                }
            }
        }

        /// <summary>
        /// 清空临时存储区所有参数
        /// </summary>
        public void ClearTemp()
        {
            this._tempDic.Clear();
        }

        #endregion



        #region 获取参数

        /// <summary>
        /// 判断是否存在指定参数名的参数值[包含返回true;不包含返回false]
        /// </summary>
        /// <param name="paraName">参数名</param>
        /// <returns>包含返回true;不包含返回false</returns>
        public bool Exist(string paraName)
        {
            if (string.IsNullOrEmpty(paraName))
            {
                throw new ArgumentNullException(nameof(paraName), "参数名不能为null或空或全空格");
            }

            if (this._dic.ContainsKey(paraName))
            {
                return true;
            }
            else
            {
                return this._tempDic.ContainsKey(paraName);
            }
        }




        /// <summary>
        /// 从完整参数字典集合中获取指定参数名的参数值.
        /// 参数名对应的值不存在,则抛出异常
        /// </summary>
        /// <typeparam name="T">参数类型</typeparam>
        /// <param name="paraName">参数名</param>
        /// <returns>参数值</returns>
        public T GetParaValue<T>(string paraName)
        {
            object value;
            if (this.TryGetParaValue(paraName, typeof(T), out value, ParaStoreType.Temp))
            {
                return (T)value;
            }

            throw new ArgumentException($"未设置\"{paraName}\"值");
        }

        /// <summary>
        /// 从完整参数字典集合中获取指定参数名的参数值.
        /// 参数名对应的值不存在,则抛出异常
        /// </summary>
        /// <typeparam name="T">参数类型</typeparam>
        /// <param name="paraName">参数名</param>
        /// <param name="priority">取值优先级选项,优先从指定区域取值,当取值失败后才从其它区域取值.默认先从临时区域</param>
        /// <returns>参数值</returns>
        public T GetParaValue<T>(string paraName, ParaStoreType priority)
        {
            object value;
            if (this.TryGetParaValue(paraName, typeof(T), out value, priority))
            {
                return (T)value;
            }

            throw new ArgumentException($"未设置\"{paraName}\"值");
        }




        /// <summary>
        /// 获取指定参数名称的值,如果值存在则将值转换为目标类型
        /// </summary>
        /// <param name="paraName">参数名</param>
        /// <param name="targetType">目标类型,如果为null则不转换</param>
        /// <returns>参数值</returns>
        /// <exception cref="ArgumentException">参数名对应的值不存在,则抛出异常</exception>
        public object GetParaValue(string paraName, Type targetType)
        {
            object value;
            if (this.TryGetParaValue(paraName, targetType, out value, ParaStoreType.Temp))
            {
                return value;
            }

            throw new ArgumentException($"未设置\"{paraName}\"值");
        }

        /// <summary>
        /// 获取指定参数名称的值,如果值存在则将值转换为目标类型
        /// </summary>
        /// <param name="paraName">参数名</param>
        /// <param name="targetType">目标类型,如果为null则不转换</param>
        /// <param name="priority">取值优先级选项,优先从指定区域取值,当取值失败后才从其它区域取值.默认先从临时区域</param>
        /// <returns>参数值</returns>
        /// <exception cref="ArgumentException">参数名对应的值不存在,则抛出异常</exception>
        public object GetParaValue(string paraName, Type targetType, ParaStoreType priority)
        {
            object value;
            if (this.TryGetParaValue(paraName, targetType, out value, priority))
            {
                return value;
            }

            throw new ArgumentException($"未设置\"{paraName}\"值");
        }



        /// <summary>
        /// 尝试获取指定参数名称的值,如果值存在则将值转换为目标类型.[获取成功返回true,失败返回false]
        /// </summary>
        /// <typeparam name="T">参数类型</typeparam>
        /// <param name="paraName">参数名</param>
        /// <param name="result">参数值</param>
        /// <returns>参数值</returns>
        public bool TryGetParaValue<T>(string paraName, out T result)
        {
            object value;
            if (this.TryGetParaValue(paraName, typeof(T), out value, ParaStoreType.Temp))
            {
                result = (T)value;
                return true;
            }
            else
            {
                result = default(T);
                return false;
            }
        }

        /// <summary>
        /// 尝试获取指定参数名称的值,如果值存在则将值转换为目标类型.[获取成功返回true,失败返回false]
        /// </summary>
        /// <typeparam name="T">参数类型</typeparam>
        /// <param name="paraName">参数名</param>
        /// <param name="result">参数值</param>
        /// <param name="priority">取值优先级选项,优先从指定区域取值,当取值失败后才从其它区域取值.默认先从临时区域</param>
        /// <returns>参数值</returns>
        public bool TryGetParaValue<T>(string paraName, out T result, ParaStoreType priority)
        {
            object value;
            if (this.TryGetParaValue(paraName, typeof(T), out value, priority))
            {
                result = (T)value;
                return true;
            }
            else
            {
                result = default(T);
                return false;
            }
        }




        /// <summary>
        /// 尝试获取指定参数名称的值,如果值存在则将值转换为目标类型.[获取成功返回true,失败返回false]
        /// </summary>
        /// <param name="paraName">参数名</param>
        /// <param name="targetType">目标类型,如果为null则不转换</param>
        /// <param name="value">参数值</param>
        /// <returns>获取成功返回true,失败返回false</returns>
        public bool TryGetParaValue(string paraName, Type targetType, out object value)
        {
            if (this.PrimitiveTryGetParaValue(paraName, targetType, out value, ParaStoreType.Temp))
            {
                if (value != null)
                {
                    if (targetType != null && targetType != value.GetType())
                    {
                        value = ConvertEx.ConvertToObject(targetType, value);
                    }

                    return true;
                }
                else
                {
                    if (targetType.IsClass ||
                        targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
                    {
                        return true;
                    }

                    ZLoger.Warn($"参数\"{paraName}\"对应的数据类型为\"{targetType.FullName}\",但值为null,转换失败");
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 尝试获取指定参数名称的值,如果值存在则将值转换为目标类型.[获取成功返回true,失败返回false]
        /// </summary>
        /// <param name="paraName">参数名</param>
        /// <param name="targetType">目标类型,如果为null则不转换</param>
        /// <param name="value">参数值</param>
        /// <param name="priority">取值优先级选项,优先从指定区域取值,当取值失败后才从其它区域取值.默认先从临时区域</param>
        /// <returns>获取成功返回true,失败返回false</returns>
        public bool TryGetParaValue(string paraName, Type targetType, out object value, ParaStoreType priority)
        {
            if (this.PrimitiveTryGetParaValue(paraName, targetType, out value, priority))
            {
                if (value != null)
                {
                    if (targetType != null && targetType != value.GetType())
                    {
                        value = ConvertEx.ConvertToObject(targetType, value);
                    }

                    return true;
                }
                else
                {
                    if (targetType.IsClass ||
                        targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
                    {
                        return true;
                    }

                    ZLoger.Warn($"参数\"{paraName}\"对应的数据类型为\"{targetType.FullName}\",但值为null,转换失败");
                    return false;
                }
            }
            else
            {
                return false;
            }
        }




        /// <summary>
        /// 尝试获取指定参数名称的值,如果值存在则获取成功.[获取成功返回true,失败返回false]
        /// </summary>
        /// <param name="paraName">参数名</param>
        /// <param name="value">参数值</param>
        /// <returns>获取成功返回true,失败返回false</returns>
        public bool TryGetParaValue(string paraName, out object value)
        {
            return this.PrimitiveTryGetParaValue(paraName, null, out value, ParaStoreType.Temp);
        }

        /// <summary>
        /// 尝试获取指定参数名称的值,如果值存在则获取成功.[获取成功返回true,失败返回false]
        /// </summary>
        /// <param name="paraName">参数名</param>
        /// <param name="value">参数值</param>
        /// <param name="priority">取值优先级选项,优先从指定区域取值,当取值失败后才从其它区域取值.默认先从临时区域</param>
        /// <returns>获取成功返回true,失败返回false</returns>
        public bool TryGetParaValue(string paraName, out object value, ParaStoreType priority)
        {
            return this.PrimitiveTryGetParaValue(paraName, null, out value, priority);
        }



        /// <summary>
        /// 尝试获取指定参数名称的值,如果值存在则将值转换为目标类型.[获取成功返回true,失败返回false]
        /// </summary>
        /// <param name="paraName">参数名</param>
        /// <param name="targetType">目标类型</param>
        /// <param name="value">参数值</param>
        /// <param name="priority">取值优先级选项,优先从指定区域取值,当取值失败后才从其它区域取值</param>
        /// <returns>获取成功返回true,失败返回false</returns>
        protected bool PrimitiveTryGetParaValue(string paraName, Type targetType, out object value, ParaStoreType priority)
        {
            if (string.IsNullOrEmpty(paraName))
            {
                throw new ArgumentNullException(nameof(paraName), "参数名不能为null或空或全空格");
            }

            if (priority == ParaStoreType.Temp)
            {
                if (this._tempDic.TryGetValue(paraName, out value))
                {
                    return true;
                }

                if (this._dic.TryGetValue(paraName, out value))
                {
                    return true;
                }
            }
            else
            {
                if (this._dic.TryGetValue(paraName, out value))
                {
                    return true;
                }

                if (this._tempDic.TryGetValue(paraName, out value))
                {
                    return true;
                }
            }

            var handler = this._resolving;
            if (handler == null)
            {
                return false;
            }
            else
            {
                var args = new ParaResolveEventArgs(paraName, targetType);
                handler(this, args);
                if (args.Succes)
                {
                    value = args.Value;
                    this._dic[paraName] = value;
                    if (this.HasParaChangedNotify())
                    {
                        this.OnRaiseParaChanged(new ParaChangeArgs(new List<ParaChangeItem>() { new ParaChangeItem(paraName, value) }, null, null));
                    }
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }


        #endregion



        #region 参数ToString

        /// <summary>
        /// 重写ToString
        /// </summary>
        /// <param name="paraNameGroup">参数名描述组信息</param>
        /// <param name="resolveParaNames">通过ParaResolve事件解决参数默认值的参数名称集合</param>
        /// <returns>String</returns>
        public string ToString(IValueDescriptionGroup paraNameGroup, IEnumerable<string> resolveParaNames)
        {
            if (paraNameGroup == null && resolveParaNames == null)
            {
                return this.ToString();
            }

            StringBuilder sb = new StringBuilder();
            List<string> existDefaultParaNameList = null;
            string displayName;

            //正向遍历
            foreach (var kv in this._dic)
            {
                if (paraNameGroup != null && paraNameGroup.TryGetNameByValue(kv.Key, out displayName))
                {
                    sb.Append(displayName);
                    sb.Append("(");
                    sb.Append(kv.Key);
                    sb.Append("):");
                }
                else
                {
                    sb.Append(kv.Key);
                    sb.Append(":");
                }

                sb.AppendLine(kv.Value == null ? String.Empty : kv.Value.ToString());

                if (resolveParaNames != null && resolveParaNames.Contains(kv.Key))
                {
                    if (existDefaultParaNameList == null)
                    {
                        existDefaultParaNameList = new List<string>();
                    }
                    existDefaultParaNameList.Add(kv.Key);
                }
            }

            //反向遍历
            if (resolveParaNames != null)
            {
                object value;
                foreach (string paraName in resolveParaNames)
                {
                    if (existDefaultParaNameList != null && existDefaultParaNameList.Contains(paraName))
                    {
                        continue;
                    }

                    this.PrimitiveTryGetParaValue(paraName, null, out value, ParaStoreType.Temp);
                    if (paraNameGroup != null && paraNameGroup.TryGetNameByValue(paraName, out displayName))
                    {
                        sb.Append(displayName);
                        sb.Append("(");
                        sb.Append(paraName);
                        sb.Append("):");
                    }
                    else
                    {
                        sb.Append(paraName);
                        sb.Append(":");
                    }

                    sb.AppendLine(value == null ? String.Empty : value.ToString());
                }
            }

            return sb.ToString();
        }

        /// <summary>
        /// 重写ToString
        /// </summary>
        /// <returns>String</returns>
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            foreach (var kv in this._dic)
            {
                sb.Append(kv.Key);
                sb.Append(":");
                sb.AppendLine(kv.Value == null ? String.Empty : kv.Value.ToString());
            }

            return sb.ToString();
        }

        #endregion

    }

}
